﻿using FlyIL.Misc;
using System;
using System.Collections.Generic;


namespace FlyIL.Trace;


public static partial class Tracer
{

    /// <summary>
    /// 自上往下 检查 是否有被更改 
    /// </summary>
    public static bool HasAlter(this Context vcontext, Inst begin, Inst end, ref Operand op, List<Inst> exclude = null)
    {

        if (begin is null || begin == end)
            return false;

        for (var it = begin; it != null; it = it == end ? null : vcontext.GetNextIfExist(it))
        {
            if (exclude != null && exclude.Contains(it))
                continue;

            if (it.WillAlter(op))
                return true;
        }

        return false;
    }

    /// <summary>
    /// 自上往下 检查 , 指定操作数 是否有参与计算 
    /// </summary>
    public static bool HasUse(this Context vcontext, Inst begin, Inst end, ref Operand op, List<Inst> exclude = null)
    {
        if (begin is null || begin == end)
            return false;


        for (var it = begin; it != null; it = it == end ? null : vcontext.GetNextIfExist(it))
        {
            if (exclude != null && exclude.Contains(it))
                continue;

            if (it.Used(op))
                return true;
        }

        return false;
    }


    internal static bool HasFactorBeenChanged(this Context context, ExpByTrace exp, Inst node, Operand operand)
    {
        if (exp is null)
            return false;

        List<OperandWrapper> wrappers = new();
        var nodes = exp.CollectDesc(exp.Depth + 999);
        if (nodes.Count == 0)
            return false;

        exp.Recursion((o) =>
        {
            if (o.Left is Operand lo && !(lo <= operand))
            {
                wrappers.Add(new OperandWrapper { ext = o.Ext, op = lo });
            }

            if (o.Right is Operand ro && !(ro <= operand))
            {
                wrappers.Add(new OperandWrapper { ext = o.Ext, op = ro });
            }
        });


        foreach (var u in wrappers)
        {
            bool found = false;
            /********
             * 这里根据 所追踪的节点 ， 是否消费了目标操作数 ， 这里是一个隐式变量 
             * 决定如何 追踪被修改 
             * ****************/
            if (node.Used(operand))
                found = context.HasAlter(begin: u.ext, end: node, op: ref u.op, exclude: null);
            else
                found = context.HasAlter(begin: u.ext, end: node, op: ref u.op, exclude: nodes);

            if (found)
            {
                return true;
            }
        }

        return false;

    }

    /// <summary>
    /// 追踪 参数,  是否有更改 
    /// !!! 这里使用的值参, 意即 追踪中参数会变化 
    /// </summary>
    //public static bool TraceAlter(this Context vcontext, Inst begin, Inst end, Operand target, List<Inst> exclude = null)
    //{
    //    var esp = OperandMaker._regs_[vcontext.RegSp];
    //    var t = target;

    //    for (var it = begin; it != null; it = it == end ? null : vcontext.GetNextIfExist(it))
    //    {
    //        var inst = it.Value;

    //        /// 如果是 push , 且包含此节点 , 则认为中间变量 转移到了栈中 , 原变量不再监视 
    //        if (exclude != null && exclude.Contains(it))
    //        {
    //            /// 这里需要转换为 栈变量 , 继续追踪  
    //            if (inst.Opt == Opt.push && inst.O1 != esp && t == inst.O1)
    //            {
    //                t = Operand.Make(t.ByteSize, vcontext.RegSp, 0);
    //            }
    //        }


    //        if (t.IsStackValue)
    //        {
    //            int? spIndex = inst.SpVariety;

    //            /// 追踪的 操作数， 包含esp 或 rsp 的情况
    //            if (spIndex != null && spIndex != 0 && t == (esp))
    //                return true;

    //            if (spIndex == null)
    //                throw new Exception("无法计算栈深度");

    //            if (spIndex != 0)
    //            {
    //                /// 如果栈有变化 ，修正 要监视的 栈操作数 
    //                t.u32 += (uint)spIndex;
    //            }

    //        }


    //        if (exclude != null && exclude.Contains(it))
    //        {

    //            /// 类似于 mov eax, [eax] , 这种情况依然需要判断 是否被消费 
    //            if (exclude != null && !inst.Used(t))
    //                continue;
    //        }


    //        if (inst.WillAlter(t) || inst.WillAlterBaseIndex(t))
    //        {
    //            return true;
    //        }


    //    }



    //    return false;
    //}


}
